import { PrismaClient } from '@prisma/client';
import fs from 'fs';
import path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);
const prisma = new PrismaClient();

const BACKUP_DIR = path.join(process.cwd(), '../backups');
const DB_PATH = path.join(process.cwd(), '../data/2fa.db');

/**
 * 创建备份目录
 */
function ensureBackupDir() {
  if (!fs.existsSync(BACKUP_DIR)) {
    fs.mkdirSync(BACKUP_DIR, { recursive: true });
  }
}

/**
 * 生成备份文件名
 */
function getBackupFileName() {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
  return `2fa_backup_${timestamp}.db`;
}

/**
 * 执行数据库备份
 */
async function backupDatabase() {
  try {
    console.log('🔄 开始备份数据库...');
    
    ensureBackupDir();
    
    const backupFile = path.join(BACKUP_DIR, getBackupFileName());
    
    // 使用SQLite的VACUUM INTO命令创建备份
    await prisma.$executeRawUnsafe(`VACUUM INTO '${backupFile}'`);
    
    // 获取文件大小
    const stats = fs.statSync(backupFile);
    const sizeInMB = (stats.size / (1024 * 1024)).toFixed(2);
    
    console.log(`✓ 备份成功！`);
    console.log(`  文件: ${backupFile}`);
    console.log(`  大小: ${sizeInMB} MB`);
    
    // 压缩备份文件
    console.log('🔄 压缩备份文件...');
    const gzipFile = `${backupFile}.gz`;
    
    try {
      await execAsync(`gzip -f "${backupFile}"`);
      const gzipStats = fs.statSync(gzipFile);
      const gzipSizeInMB = (gzipStats.size / (1024 * 1024)).toFixed(2);
      
      console.log(`✓ 压缩完成！`);
      console.log(`  压缩后: ${gzipSizeInMB} MB`);
    } catch (gzipError) {
      console.warn('⚠️  压缩失败（可能没有安装gzip），但备份文件已创建');
    }
    
    // 清理旧备份（保留最近7个）
    await cleanOldBackups();
    
    return backupFile;
  } catch (error) {
    console.error('❌ 备份失败:', error.message);
    throw error;
  }
}

/**
 * 清理旧备份文件
 */
async function cleanOldBackups() {
  try {
    const files = fs.readdirSync(BACKUP_DIR)
      .filter(f => f.startsWith('2fa_backup_') && (f.endsWith('.db') || f.endsWith('.gz')))
      .map(f => ({
        name: f,
        path: path.join(BACKUP_DIR, f),
        time: fs.statSync(path.join(BACKUP_DIR, f)).mtime.getTime()
      }))
      .sort((a, b) => b.time - a.time);
    
    // 保留最近7个备份
    const filesToDelete = files.slice(7);
    
    if (filesToDelete.length > 0) {
      console.log(`🗑️  清理 ${filesToDelete.length} 个旧备份文件...`);
      filesToDelete.forEach(file => {
        fs.unlinkSync(file.path);
        console.log(`  删除: ${file.name}`);
      });
    }
  } catch (error) {
    console.warn('⚠️  清理旧备份时出错:', error.message);
  }
}

/**
 * 列出所有备份
 */
function listBackups() {
  try {
    if (!fs.existsSync(BACKUP_DIR)) {
      console.log('📂 备份目录不存在');
      return;
    }
    
    const files = fs.readdirSync(BACKUP_DIR)
      .filter(f => f.startsWith('2fa_backup_'))
      .map(f => {
        const filePath = path.join(BACKUP_DIR, f);
        const stats = fs.statSync(filePath);
        return {
          name: f,
          size: (stats.size / (1024 * 1024)).toFixed(2) + ' MB',
          date: stats.mtime.toLocaleString('zh-CN')
        };
      })
      .sort((a, b) => b.date.localeCompare(a.date));
    
    if (files.length === 0) {
      console.log('📂 没有找到备份文件');
      return;
    }
    
    console.log('\n📋 备份文件列表:\n');
    files.forEach((file, index) => {
      console.log(`${index + 1}. ${file.name}`);
      console.log(`   大小: ${file.size}`);
      console.log(`   日期: ${file.date}\n`);
    });
  } catch (error) {
    console.error('❌ 列出备份失败:', error.message);
  }
}

/**
 * 恢复数据库
 */
async function restoreDatabase(backupFile) {
  try {
    console.log('⚠️  警告: 恢复操作将覆盖当前数据库！');
    console.log(`将从以下文件恢复: ${backupFile}\n`);
    
    // 检查备份文件是否存在
    if (!fs.existsSync(backupFile)) {
      throw new Error('备份文件不存在');
    }
    
    // 如果是.gz文件，先解压
    let dbFile = backupFile;
    if (backupFile.endsWith('.gz')) {
      console.log('🔄 解压备份文件...');
      await execAsync(`gunzip -k -f "${backupFile}"`);
      dbFile = backupFile.replace('.gz', '');
    }
    
    // 备份当前数据库
    const currentBackup = `${DB_PATH}.before_restore`;
    if (fs.existsSync(DB_PATH)) {
      console.log('🔄 备份当前数据库...');
      fs.copyFileSync(DB_PATH, currentBackup);
      console.log(`  已保存到: ${currentBackup}`);
    }
    
    // 恢复数据库
    console.log('🔄 恢复数据库...');
    fs.copyFileSync(dbFile, DB_PATH);
    
    console.log('✓ 数据库恢复成功！');
    console.log('  如需回滚，请使用:', currentBackup);
    
  } catch (error) {
    console.error('❌ 恢复失败:', error.message);
    throw error;
  }
}

/**
 * 主函数
 */
async function main() {
  const command = process.argv[2];
  
  try {
    switch (command) {
      case 'create':
        await backupDatabase();
        break;
        
      case 'list':
        listBackups();
        break;
        
      case 'restore':
        const backupFile = process.argv[3];
        if (!backupFile) {
          console.error('❌ 请指定备份文件路径');
          console.log('使用方法: npm run backup restore <backup-file>');
          process.exit(1);
        }
        await restoreDatabase(backupFile);
        break;
        
      default:
        console.log('2FA Manager - 数据库备份工具\n');
        console.log('使用方法:');
        console.log('  npm run backup create   - 创建备份');
        console.log('  npm run backup list     - 列出所有备份');
        console.log('  npm run backup restore <file> - 恢复备份\n');
    }
  } catch (error) {
    process.exit(1);
  } finally {
    await prisma.$disconnect();
  }
}

main();

